package com.atguigu.springbootrabbitmq.controller;

import com.atguigu.springbootrabbitmq.config.DelayedQueueConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * 生产者
 * 发送延迟消息
 */
@Slf4j
@RestController
@RequestMapping("/ttl")
public class SendMsgController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //开始发消息
    @GetMapping("/sendMsg/{message}")
    public void sendMsg(@PathVariable String message) {

        log.info("当前时间:{},发送一条信息给两个TTL队列:{}",
                new Date().toString(), message);

        rabbitTemplate.convertAndSend("X", "XA",
                "消息来着TTL为10S的队列:" + message);

        rabbitTemplate.convertAndSend("X", "XB",
                "消息来着TTL为40S的队列:" + message);

    }

    /**
     * 这里看起来没什么问题,但是在最开始的时候,就介绍过如果使用在消息属性上
     * 设置TTL的方式,消息可能并不会按时死亡,因为RabbitMQ只会坚持第一个消息是否过期。
     * 如果过期则丢到死信队列,如果第一个消息的延时时长很长,而第二个消息的延时时长很短,
     * 第二个消息并不会优先得到执行。
     *
     * @param message
     * @param ttlTime
     */
    //开始发消息 消息TTL
    @GetMapping("/sendExpirationMsg/{message}/{ttlTime}")
    public void sendMsg(@PathVariable String message, @PathVariable String ttlTime) {
        log.info("当前时间: {},发送一条时长{}毫秒TTL信息给队列QC:{}",
                new Date().toString(), ttlTime, message);
        rabbitTemplate.convertAndSend("X", "XC", message, msg -> {
            //发送消息的时候 延迟时长
            msg.getMessageProperties().setExpiration(ttlTime);
            return msg;
        });
    }

    /**
     * 延时队列再需要延时处理的场景下非常有用，使用RabbitMQ来实现延时队列可以很好的
     * 利用RabbitMQ的特性，如: 消息可靠发送,消息可靠投递,死信队列来保障消息至少被消费一次
     * 以及未被正确处理的消息不会被丢弃。另外,通过RabbitMQ集群的特性,可以很好的解决单点故障问题，
     * 不会因为单个节点挂掉导致延时队列不可用或者消息丢失。
     *
     * 当然，延时队列还有很多其它选择。
     * @param message
     * @param delayTime
     */
    //开始发消息,基于插件的消息及延迟的时间,用插件解决死信队列的痛点。
    @GetMapping("/sendDelayMsg/{message}/{delayTime}")
    public void senMsg(@PathVariable String message, @PathVariable Integer delayTime) {
        log.info("当前时间: {},发送一条时长{}毫秒信息给延迟队列delayed.queue:{}",
                new Date().toString(), delayTime, message);

        rabbitTemplate.convertAndSend(DelayedQueueConfig.DELAYED_EXCHANGE_NAME, DelayedQueueConfig.DELAYED_ROUTING_KEY, message, msg -> {
            //发送消息的时候, 延迟时长
            msg.getMessageProperties().setDelay(delayTime);
            return msg;
        });
    }

}

